package com.ztesoft.web.resourcecheck;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.stereotype.Service;

import com.jcraft.jsch.JSchException;
import com.ztesoft.core.db.ds.DynamicDataSourceManager;
import com.ztesoft.core.idproduce.ISequenceGenerator;
import com.ztesoft.core.spring.context.SpringApplicationContextHolder;
import com.ztesoft.framework.exception.BaseAppException;
import com.ztesoft.framework.exception.ExceptionHandler;
import com.ztesoft.framework.log.ZTEsoftLogManager;
import com.ztesoft.framework.util.DateUtils;
import com.ztesoft.framework.util.Utils;
import com.ztesoft.iocp.cipher.util.RSAUtils;
import com.ztesoft.iocp.utils.HttpUtils;
import com.ztesoft.web.baseconfig.db.dao.DmPlanDao;
import com.ztesoft.web.baseconfig.db.dao.DmStrategyDao;
import com.ztesoft.web.baseconfig.db.dao.DmTargetTableDao;
import com.ztesoft.web.baseconfig.db.po.DmPlanPO;
import com.ztesoft.web.baseconfig.db.po.DmSrcTablePO;
import com.ztesoft.web.baseconfig.db.po.DmTargetTablePO;
import com.ztesoft.web.common.DMSConstant;
import com.ztesoft.web.common.Util;
import com.ztesoft.web.common.customdb.dao.DmSrcTableCustomDao;
import com.ztesoft.web.common.db.arg.DetectionInfoArg;
import com.ztesoft.web.common.db.arg.DmHostConnInfoArg;
import com.ztesoft.web.common.db.arg.DmIndexInfoArg;
import com.ztesoft.web.common.db.arg.SysParamArg;
import com.ztesoft.web.common.db.dao.DbBaseInfoDao;
import com.ztesoft.web.common.db.dao.DetectionInfoDao;
import com.ztesoft.web.common.db.dao.DmHostConnInfoDao;
import com.ztesoft.web.common.db.dao.DmIndexInfoDao;
import com.ztesoft.web.common.db.dao.SysParamDao;
import com.ztesoft.web.common.db.po.DbBaseInfoPO;
import com.ztesoft.web.common.db.po.DetectionInfoPO;
import com.ztesoft.web.common.db.po.DmHostConnInfoPO;
import com.ztesoft.web.common.db.po.DmIndexInfoPO;
import com.ztesoft.web.common.db.po.SysParamPO;
import com.ztesoft.web.common.vo.HostConnInfoVO;
import com.ztesoft.web.common.vo.HostConnMethodVO;
import com.ztesoft.web.common.vo.HostInfoPOJO;
import com.ztesoft.web.common.vo.TaskNotify;
import com.ztesoft.web.filecommon.db.dao.DmFDao;
import com.ztesoft.web.filecommon.db.po.DmFPO;
import com.ztesoft.web.syncbaseinfo.service.BaseInfoService;
import com.ztesoft.web.taskgenerator.db.arg.DmTaskArg;
import com.ztesoft.web.taskgenerator.db.arg.DmTaskStageArg;
import com.ztesoft.web.taskgenerator.db.dao.DmTaskDao;
import com.ztesoft.web.taskgenerator.db.dao.DmTaskStageDao;
import com.ztesoft.web.taskgenerator.db.po.DmTaskPO;
import com.ztesoft.web.taskgenerator.db.po.DmTaskStagePO;

@Service
public class ResourceCheckJob {

	private static final ZTEsoftLogManager logger = ZTEsoftLogManager
			.getLogger(ResourceCheckJob.class);
	@Autowired
	private DmFDao dmfDao;
	@Autowired
	private DmTaskDao dmTaskDao;
	@Autowired
	private DmTaskStageDao dmTaskStageDao;
	@Autowired
	private DmPlanDao dmPlanDao;
	@Autowired
	private SysParamDao sysParamDao;
	@Autowired
	private DmTargetTableDao dmTargetTableDao;
	@Autowired
	private DmSrcTableCustomDao srcTableCustomDao;
	@Autowired
	private DbBaseInfoDao dbBaseInfoDao;
	@Autowired
	private DmHostConnInfoDao dmHostConnInfoDao;
	@Autowired
	private DmStrategyDao dmStrategyDao;
	@Autowired
	private DynamicDataSourceManager dynamicDataSourceManager;// 数据库 连接
	@Autowired
	private BaseInfoService baseInfoService;
	@Autowired
	private DetectionInfoDao detectionInfoDao;
	@Resource(name = "sequenceProcGenerator")
	private ISequenceGenerator sequenceGenerator;// 主键生成器
	
	@Autowired
	private HostResCheck hostResCheck; // add by lin.wb

	@Autowired
	private LModeCheck lModeCheck;
	
	@Autowired
	private IdxCheck idxCheck;
	
	@Autowired
	private DmIndexInfoDao indexInfoDao;
	
	Map<String, Integer> hostMap;// 主机连接基础信息
	private String busStartTime;// 营业开始时间
	private String busEndTime;// 营业结束时间
	private Float cpuUsedThreshold;// cpu使用率
	private Float memUsedThreshold;// 内存使用率
	private Float tbsUsedThreshold;// 剩余表空间
	private String collectUrl;// 告警通知推送,IOCP提供的接口
	private String cleanUrl;// 告警消除通知推送,IOCP提供的接口
	private String subSysIp;// 子系统IP
	private String subSysPort;// 子系统端口


	public void checkResource() {
		logger.info("==================开始检测营业时间、cpu、内存信息=============================");
		initSysParam();		
		List<DmTaskPO> taskList = qryTaskByState("02P", "00R");//系统暂停、执行中
		logger.debug("查询执行中和系统暂停的任务实例列表{0}",taskList);
		
		for (DmTaskPO dmTaskPO : taskList) {
			logger.debug("开始检测任务实例TaskId：{0}",dmTaskPO.getDmTaskId());
			
			/*
			 * 自动执行的监测营业时间~
			 */
			DmPlanPO plan = dmPlanDao.selectByPrimaryKey(dmTaskPO.getDmPlanId());
			if (DMSConstant.EXEC_TYPE_AUTO.equals(plan.getExecType())) {
				DateFormat df = DateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.UK);// 只显示出时分秒
				String nowTime = df.format(DateUtils.getNowDate()).replace(":", "");				
				TaskNotify notify = DMSConstant.taskInstList.get(dmTaskPO.getDmTaskId());
				if (Utils.isEmpty(notify)) notify = new TaskNotify();
				
				if (Utils.isInRange(nowTime, busStartTime, busEndTime)) {
					notify.setDealType("BUS-TIME");
					notify.setStatus(DMSConstant.Status.SYSPAUSE.toString());
					notify.setDealDesc("当前时间" + nowTime + "在营业时间["+busStartTime+","+busEndTime+"]内，需要暂停任务TASKID"+dmTaskPO.getDmTaskId());
					DMSConstant.taskInstList.put(dmTaskPO.getDmTaskId(), notify);
					logger.info(notify.getDealDesc());
					continue;//下个循环~
				}
			}
			boolean isOk = true;
			//表空间监测 or 主机(cpu/内存)监测 or 索引、锁模式比较 
			if (1 == (int)plan.getSourceType() && !checkTableSpaceForTable(dmTaskPO) 
					|| !checkHostForTable(dmTaskPO) 
					|| !checkIdxAndLMode(dmTaskPO)) {
				isOk = false;//下个循环~
			} else if (2 == (int)plan.getSourceType()) {//文件的资源检测 
				DmTaskStageArg taskStageArg = new DmTaskStageArg();
				DmTaskStageArg.DmTaskStageCriteria taskStageCriteria = taskStageArg.createCriteria();
				taskStageCriteria.andDmTaskIdEqualTo(dmTaskPO.getDmTaskId());
				taskStageCriteria.andStageEqualTo(0);//体检
				taskStageCriteria.andStateNotEqualTo("00F");
				List<DmTaskStagePO> dmTaskStagePOList = dmTaskStageDao.selectByArg(taskStageArg);
				for (DmTaskStagePO po : dmTaskStagePOList) {				
					String tableName = "DM_F_"+po.getDmStrategyId();
					List<DmFPO> dfList = dmfDao.selectDmF(tableName);
					for (DmFPO dmFPO : dfList) {
						hostMap.put(dmFPO.getSrcIp(), 1);
						hostMap.put(dmFPO.getTargetIp(), 2);
					}
				}
				if (!checkHostForTable(dmTaskPO)) {
					isOk = false;//下个循环~
				}
			}
			
			/*以上均校验通过，则任务02P->00T*/
			if (isOk && DMSConstant.Status.SYSPAUSE.toString().equals(dmTaskPO.getState())) {
				sysPause2doTask(dmTaskPO);
			}
			logger.debug("结束检测任务实例TaskId：{0}",dmTaskPO.getDmTaskId());
		}
		logger.info("==================结束检测营业时间、cpu、内存信息=============================");
	}

	/**
	 * 查询源主表、遍历处理源主表比较索引、锁信息
	 * @param dmTaskPO
	 * @return
	 */
	private boolean checkIdxAndLMode(DmTaskPO dmTaskPO) {
		logger.info("查询源主表、遍历处理源主表比较索引、锁信息taskid:{0}",dmTaskPO.getDmTaskId());
		List<DmSrcTablePO> srcTableList = srcTableCustomDao.selectByTaskId(dmTaskPO.getDmTaskId());
		if (Utils.isEmpty(srcTableList)) {
			return true;
		}
		for (DmSrcTablePO srcTablePO : srcTableList) {
			String lockMode = srcTablePO.getLockMode();
			Integer dbLinkId = srcTablePO.getDbLinkId();
			String dbUserName = srcTablePO.getDbUserName();
			try {
				String[] dbConfig = baseInfoService.getDbConfig(dbLinkId, dbUserName);

				//informix锁模式
				StringBuilder descBuilder = new StringBuilder();
				if (dbConfig[0].equals("informix")) {
					String checkLockMode = lModeCheck.qryIfxLMode(dbLinkId, srcTablePO.getTableName(), dbConfig);
					logger.info("表{0}锁模式为{1},原锁模式为{2}",srcTablePO.getTableName(), checkLockMode, lockMode);
					if (!checkLockMode.equals(lockMode)) {
						//不一致抛告警结束
						TaskNotify notify = DMSConstant.taskInstList.get(dmTaskPO.getDmTaskId());
						if (Utils.isEmpty(notify)) notify = new TaskNotify();
						notify.setDealType("LMODE_CHANGED");
//						notify.setStatus(DMSConstant.Status.SYSPAUSE.toString());
						descBuilder.append(srcTablePO.getTableName()).append("的锁模式发生变化，原为")
							.append(lockMode).append("现为").append(checkLockMode)
							.append("TaskId:").append(dmTaskPO.getDmTaskId());
						notify.setDealDesc(descBuilder.toString());
//						DMSConstant.taskInstList.put(dmTaskPO.getDmTaskId(), notify);
						pushMsg2IOCP(notify.getDealType()+dmTaskPO.getDmTaskId(), notify.getDealDesc(), dmTaskPO.getDmTaskId()+"_TABLE_LMODE_WARNING");
						return false;
					}
				}
				//数据库索引比较
				List<DmIndexInfoPO> indexInfoPOList = idxCheck.qryIdxForPO(dbLinkId, srcTablePO.getTableName(), dbConfig);
				DmIndexInfoArg arg = new DmIndexInfoArg();
				DmIndexInfoArg.DmIndexInfoCriteria criteria = arg.createCriteria();
				criteria.andDataIdEqualTo(srcTablePO.getSourceDataId());
				criteria.andTableNameEqualTo(srcTablePO.getTableName());
				criteria.andStateEqualTo("00A");
				List<DmIndexInfoPO> dmIndexInfoPOList = indexInfoDao.selectByArg_(arg);
				logger.info("表{0}索引为{1},\r\n原索引为{2}",srcTablePO.getTableName(), indexInfoPOList, dmIndexInfoPOList);
				if(!CollectionUtils.isEqualCollection(indexInfoPOList, dmIndexInfoPOList)) {
					//不一致抛告警结束
					//DM_TASK.index_change_flag为T 
					TaskNotify notify = DMSConstant.taskInstList.get(dmTaskPO.getDmTaskId());
					if (Utils.isEmpty(notify)) notify = new TaskNotify();
					notify.setDealType("IDX_CHANGED");
					notify.setStatus(DMSConstant.Status.SYSPAUSE.toString());
					descBuilder.append(srcTablePO.getTableName()).append("的索引发生变更")
						.append("TaskId:").append(dmTaskPO.getDmTaskId());
					notify.setDealDesc(descBuilder.toString());
					DMSConstant.taskInstList.put(dmTaskPO.getDmTaskId(), notify);
					
					pushMsg2IOCP(notify.getDealType()+dmTaskPO.getDmTaskId(), notify.getDealDesc(), dmTaskPO.getDmTaskId()+"_TABLE_INDEX_WARNING");
					
					dmTaskPO.setIndexChangeFlag("T");
					dmTaskDao.updateByPrimaryKeySelective(dmTaskPO);
					return false;
				}
				
			} catch (Exception e) {
				//监测异常告警结束
				logger.error("索引、锁模式监测异常", e);
				pushMsg2IOCP(dmTaskPO.getDmTaskId()+"_锁模式、索引监测异常", e.getMessage(), e.getMessage());
				return false;
			}
			
		}
		return true;
	}

	/**
	 * 根据状态查询任务
	 * @param state
	 * @return
	 */
	private List<DmTaskPO> qryTaskByState(String ... state) {
		List<String> stateList = new ArrayList<String>();
		for (String stateStr : state) {
			stateList.add(stateStr);
		}
		DmTaskArg dmTaskArg = new DmTaskArg();
		DmTaskArg.DmTaskCriteria dmTaskCriteria = dmTaskArg.createCriteria();
		dmTaskCriteria.andStateIn(stateList);
		return dmTaskDao.selectByArg(dmTaskArg);
	}

	/**
	 * 暂停任务写内存状态且通知
	 * 全部检测通过 更新任务为待执行
	 * @param dmTaskPO
	 */
	private void sysPause2doTask(DmTaskPO dmTaskPO) {
		logger.debug("|全部检测通过时，若该任务状态为系统暂停（STATE='02P'）则需要从新触发执行，更新任务,任务环节状态为待执行|");
		dmTaskPO.setState(DMSConstant.Status.PENDING.toString());
		dmTaskDao.updateByPrimaryKeySelective(dmTaskPO);
		TaskNotify notify = DMSConstant.taskInstList.get(dmTaskPO.getDmTaskId());
		if (Utils.isEmpty(notify)) {
			notify = new TaskNotify();
			DetectionInfoArg arg = new DetectionInfoArg();
			DetectionInfoArg.DetectionInfoCriteria c = arg.createCriteria();
			c.andDmTaskIdEqualTo(dmTaskPO.getDmTaskId());
			c.andWarningFlagEqualTo(1);
			List<DetectionInfoPO> list = detectionInfoDao.selectByArg(arg);
			if (!Utils.isEmpty(list)) {						
				notify.setDealType(qryDealType(list.get(0).getDetectionItemName()));
			}
		}
		// 推送到IOCP
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("warningName", notify.getDealType()+ dmTaskPO.getDmTaskId());
		paramMap.put("warningLevel", "urgent");
		paramMap.put("warningType", "10A");
		paramMap.put("recoverTime", DateUtils.getCurrentDate().replace(" ", "%20"));
		paramMap.put("subSysIp", subSysIp);
		paramMap.put("subSysPort", subSysPort);
		pushMsg2IOCP(paramMap, cleanUrl);
		notify.setDealType("");
		notify.setStatus(DMSConstant.Status.PENDING.toString());
		notify.setDealDesc("");
		DMSConstant.taskInstList.put(dmTaskPO.getDmTaskId(), notify);
		logger.debug(dmTaskPO.getDmTaskId() + "的修改后编码："+ notify.getStatus());
	}

	/**
	 * 检测主机资源（表）
	 * 
	 * @param dmTaskPO
	 * @return 是否继续执行
	 */
	private boolean checkHostForTable(DmTaskPO dmTaskPO) {
		logger.debug("检测主机信息DMTASKID={0} BEGIN...",dmTaskPO.getDmTaskId());
		boolean flag = false;
		Map<String, HostConnMethodVO> connMethodMap = null;// 主机连接信息
		for (Entry<String, Integer> dbBaseInfoEntry : hostMap.entrySet()) {
//			DbBaseInfoPO dbBaseInfoPO = dbBaseInfoEntry.getValue();
			DmHostConnInfoArg connInfoArg = new DmHostConnInfoArg();
			DmHostConnInfoArg.DmHostConnInfoCriteria connInfoCriteria = connInfoArg.createCriteria();
			connInfoCriteria.andIpEqualTo(dbBaseInfoEntry.getKey());
			List<DmHostConnInfoPO> tempList = dmHostConnInfoDao
					.selectByArg(connInfoArg);
			if (tempList.size() > 0) {
				DmHostConnInfoPO hostPo = tempList.get(0);
				logger.info("监测主机{0}",hostPo);
				String osType = hostPo.getOsType();// 操作类型
				HostConnInfoVO hostConnInfoVO;// = new HostConnInfoVO();
				try {
					logger.debug("|获取主机连接信息|");
					hostConnInfoVO = baseInfoService.queryHostConn(hostPo.getHostId());
				} catch (BaseAppException e) {
					logger.error("|获取主机信息异常|", e);
					return false;
				}
				connMethodMap = new HashMap<String, HostConnMethodVO>();
				List<HostConnMethodVO> hostList = hostConnInfoVO.getHostConnMethod();
				for (HostConnMethodVO vo : hostList) {
					connMethodMap.put(vo.getConnMethod().toLowerCase(), vo);
				}
				logger.info("|查询CPU使用率|");
				String cpuValue = "0";
				try {
					 if (!Utils.isEmpty(connMethodMap.get(DMSConstant.HOST_LINK_SSH))) {
						cpuValue = sshToCPU(connMethodMap.get(DMSConstant.HOST_LINK_SSH),hostPo);
					} else if (!Utils.isEmpty(connMethodMap.get(DMSConstant.HOST_LINK_TELNET))) {
						cpuValue = telnetToCPU(connMethodMap.get(DMSConstant.HOST_LINK_TELNET),hostPo);
					} else if (!Utils.isEmpty(connMethodMap.get(DMSConstant.HOST_LINK_FTP))) {
						logger.error("未实行连接方式为FTP cpu监测");
						return false;
					} else {
						logger.error("连接方式未配置无法进行cpu监测");
						return false;
					}
				} catch (Exception e) {
					logger.error("cpu监测异常",e);
					return false;
				}
				Float cpuUsed = BigDecimal.valueOf(100 - Float.valueOf(cpuValue))
						.setScale(2, RoundingMode.HALF_UP).floatValue();
				DetectionInfoPO po = new DetectionInfoPO();
				po.setDmTaskId(dmTaskPO.getDmTaskId());
				po.setDetectionType(DMSConstant.DETECTION_TYPE_TABLE);
				po.setDetectionObjectType(osType);
				po.setDetectionObjectId(hostPo.getHostId());
				po.setDetectionItemName(DMSConstant.DETECTION_ITEM_CPU);
				po.setDetectionTotalResult(BigDecimal.valueOf(100));
				po.setDetectionUsedResult(BigDecimal.valueOf(cpuUsed));
				po.setDetectDate(DateUtils.getNowDate());
				po.setNodeId(dmTaskPO.getNodeId());
				po.setWarningFlag(0);
				if (cpuUsedThreshold < cpuUsed) {
					po.setWarningFlag(1);
					TaskNotify notify = DMSConstant.taskInstList.get(dmTaskPO.getDmTaskId());
					if (Utils.isEmpty(notify)) notify = new TaskNotify();
					logger.debug(dmTaskPO.getDmTaskId() + "的修改前编码：" + notify.getStatus());
					notify.setDealType("CPU-USED");
					notify.setStatus(DMSConstant.Status.SYSPAUSE.toString());
					notify.setDealDesc("主机 " + hostPo.getIp()
							+ " CPU使用率为" + cpuUsed + "%，达到系统设置的阀值"
							+ cpuUsedThreshold + "%，需要暂停任务TASKID"+dmTaskPO.getDmTaskId());
					DMSConstant.taskInstList.put(dmTaskPO.getDmTaskId(), notify);
					logger.debug(dmTaskPO.getDmTaskId() + "的修改后编码：" + notify.getStatus());
					logger.debug("向IOCP推送告警信息 :");
					pushMsg2IOCP(notify.getDealType() + dmTaskPO.getDmTaskId(), 
							notify.getDealDesc(), notify.getDealDesc());
					flag = true;
				}
				saveOrUpdateData(po);
				if (flag) return false;
				
				logger.info("|查询内存使用率|");
				List<Float> memList = new ArrayList<Float>();
				try {
					 if (!Utils.isEmpty(connMethodMap.get(DMSConstant.HOST_LINK_SSH))) {
						memList = sshToMEM(connMethodMap.get(DMSConstant.HOST_LINK_SSH),hostPo);
					} else if (!Utils.isEmpty(connMethodMap.get(DMSConstant.HOST_LINK_TELNET))) {
						memList = telnetToMEM(connMethodMap.get(DMSConstant.HOST_LINK_TELNET),hostPo);
					} /*else if (!Utils.isEmpty(connMethodMap.get(DMSConstant.HOST_LINK_FTP))) {
						logger.error(Thread.currentThread()+"未实行连接方式为FTP mem监测");
						return false;
					} else {
						logger.error(Thread.currentThread()+"连接方式未配置无法进行mem监测");
						return false;
					}*/
				} catch (Exception e) {
					logger.error("",e);
					return false;
				}
				
				Float total = memList.get(0);
				Float avm = memList.get(1);
				// modified
				if (hostPo.getOsType().toLowerCase().equals("linux")) {
					total += avm;
				}
				DetectionInfoPO record = new DetectionInfoPO();
				record.setDmTaskId(dmTaskPO.getDmTaskId());
				record.setDetectionType(DMSConstant.DETECTION_TYPE_TABLE);
				record.setDetectionObjectType(osType);
				record.setDetectionObjectId(hostPo.getHostId());
				record.setDetectionItemName(DMSConstant.DETECTION_ITEM_MEMORY);
				record.setDetectionTotalResult(BigDecimal.valueOf(total / 8 / 1024).setScale(2,RoundingMode.HALF_UP));
				record.setDetectionUsedResult(BigDecimal.valueOf(avm / 8 / 1024).setScale(2,RoundingMode.HALF_UP));
				record.setDetectDate(DateUtils.getNowDate());
				record.setNodeId(dmTaskPO.getNodeId());
				BigDecimal memUsedThresholdValue = BigDecimal.valueOf(100 * avm / total).setScale(2, RoundingMode.HALF_UP);
				record.setWarningFlag(0);
				if (memUsedThreshold < memUsedThresholdValue.floatValue()) {
					record.setWarningFlag(1);
					TaskNotify notify = DMSConstant.taskInstList.get(dmTaskPO.getDmTaskId());
					if (Utils.isEmpty(notify)) notify = new TaskNotify();
					logger.debug(dmTaskPO.getDmTaskId() + "的修改前编码："+ notify.getStatus());
					notify.setDealType("MEM-USED");
					notify.setStatus(DMSConstant.Status.SYSPAUSE.toString());
					notify.setDealDesc("主机 " + hostPo.getIp()+ " 内存使用率为" + memUsedThresholdValue+ "%，"
							+ "达到系统设置的阀值" + memUsedThreshold+ "%，需要暂停任务");
					DMSConstant.taskInstList.put(dmTaskPO.getDmTaskId(), notify);
					logger.debug(dmTaskPO.getDmTaskId() + "的修改后编码："+ notify.getStatus());
					// 向IOCP推送告警信息
					pushMsg2IOCP(notify.getDealType()+ dmTaskPO.getDmTaskId(), 
							notify.getDealDesc(), notify.getDealDesc());
					logger.info("向IOCP推送告警信息 ok");
					flag = true;
				}
				saveOrUpdateData(record);
				if (flag) return false;
			} else { //
				logger.info("未配置该主机信息数据|请于IOCP配置该IP:{0}主机信息",dbBaseInfoEntry.getKey());
				pushMsg2IOCP("主机信息配置","IP["+dbBaseInfoEntry.getKey()+"]主机信息未配置,请于IOCP配置后,消除该告警信息!!!",
						"IP["+dbBaseInfoEntry.getKey()+"]主机信息未配置,请于IOCP配置后,消除该告警信息!!!");
				return true;
			}
		}
		return true;
	}

	/**
	 * ssh方式检测内存使用
	 * 
	 * @param HostConnMethodVO
	 * @param hostPo
	 * @return
	 * @throws BaseAppException
	 * @throws JSchException
	 * @throws IOException
	 */
	private List<Float> sshToMEM(HostConnMethodVO vo, DmHostConnInfoPO hostPo) throws Exception {
		logger.info("ssh方式检测内存使用...");
		List<Float> list = new ArrayList<Float>(2);
		String pwd = RSAUtils.decryptString(vo.getPassword());
		HostInfoPOJO hostInfoPOJO = null;
		try {
			hostInfoPOJO = new HostInfoPOJO(hostPo.getOsType(), hostPo.getIp(), vo.getUserName(), pwd, vo.getPort(), false);
			hostResCheck.setCheckStrategy(SpringApplicationContextHolder.getBean(SSHCheckStrategy.class));
			list.add(Float.valueOf(hostResCheck.getCheckData(hostInfoPOJO, DMSConstant.CHECK_CMD_MEM)));
			list.add(Float.valueOf(hostResCheck.getCheckData(hostInfoPOJO, DMSConstant.CHECK_CMD_USED_MEM)));
		} catch (Exception e) {
			logger.error("执行ssh监测内存异常",e);
			ExceptionHandler.publish("执行ssh监测内存异常", e);
			return null;
		} 
		logger.info("ssh内存监测结果:"+list);
		return list;
	}

	/**
	 * Telnet方式检测内存使用
	 * 
	 * @param HostConnMethodVO
	 * @param hostPo
	 * @return
	 * @throws Exception
	 * @throws IllegalStateException
	 * @throws NoSuchElementException
	 */
	private List<Float> telnetToMEM(HostConnMethodVO vo, DmHostConnInfoPO hostPo)
			throws NoSuchElementException, IllegalStateException, Exception {
		logger.debug("Telnet方式检测内存使用");
		List<Float> list = new ArrayList<Float>();
		HostInfoPOJO hostInfoPOJO = null;
		String total = null;
		String used = null;
		String pwd = RSAUtils.decryptString(vo.getPassword());
		try {
			hostInfoPOJO = new HostInfoPOJO(hostPo.getOsType(), hostPo.getIp(), vo.getUserName(), pwd, vo.getPort(), false);
			hostResCheck.setCheckStrategy(SpringApplicationContextHolder.getBean(TelNetCheckStrategy.class));
			total = hostResCheck.getCheckData(hostInfoPOJO, DMSConstant.CHECK_CMD_MEM);
			used = hostResCheck.getCheckData(hostInfoPOJO, DMSConstant.CHECK_CMD_USED_MEM);
			total = Util.dealResult(total); 
			used = Util.dealResult(used); 
			list.add(Float.valueOf(total));
			list.add(Float.valueOf(used));
		} catch (Exception e) {
				logger.error("执行telnet监测内存异常",e);
				ExceptionHandler.publish("执行telnet监测内存异常", e);
				return null;
		} 
		return list;
	}


	/**
	 * ssh方式检测CPU使用
	 * 
	 * @param HostConnMethodVO
	 * @param hostPo
	 * @return
	 * @throws JSchException
	 * @throws IOException
	 * @throws BaseAppException
	 */
	private String sshToCPU(HostConnMethodVO vo, DmHostConnInfoPO hostPo)
			throws BaseAppException {
		logger.debug("ssh方式检测CPU使用");
		HostInfoPOJO hostInfoPOJO = null;
		String cpuValue = "0";
		String pwd = RSAUtils.decryptString(vo.getPassword());
		try {
			hostInfoPOJO = new HostInfoPOJO(hostPo.getOsType(), hostPo.getIp(), vo.getUserName(), pwd, vo.getPort(), false);
			hostResCheck.setCheckStrategy(SpringApplicationContextHolder.getBean(SSHCheckStrategy.class));
			cpuValue = hostResCheck.getCheckData(hostInfoPOJO, DMSConstant.CHECK_CMD_CPU);
		} catch (Exception e) {
			throw ExceptionHandler.publish("执行ssh监测cpu异常", e);
		} 

		logger.info("IP:" + hostPo.getIp() +"执行ssh方式检测CPU使用结果：" + cpuValue);
		return cpuValue;
	}

	/**
	 * telnet方式检测CPU使用
	 * 
	 * @param HostConnMethodVO
	 * @param hostPo
	 * @return
	 * @throws Exception
	 * @throws IllegalStateException
	 * @throws NoSuchElementException
	 */
	private String telnetToCPU(HostConnMethodVO vo, DmHostConnInfoPO hostPo) throws BaseAppException {
		logger.info("telnet方式检测CPU使用");
		HostInfoPOJO hostInfoPOJO = null;
		String cpuValue = "0";
		String pwd = RSAUtils.decryptString(vo.getPassword());
		try {
			hostInfoPOJO = new HostInfoPOJO(hostPo.getOsType(), hostPo.getIp(), vo.getUserName(), pwd, vo.getPort(), false);
			hostResCheck.setCheckStrategy(SpringApplicationContextHolder.getBean(TelNetCheckStrategy.class));
			cpuValue = hostResCheck.getCheckData(hostInfoPOJO, DMSConstant.CHECK_CMD_CPU);
			cpuValue = Util.dealResult(cpuValue);
		} catch (Exception e) {
			throw ExceptionHandler.publish("执行telnet监测cpu异常", e);
		} 
		
		return cpuValue;
	}

	/**
	 * 检测表空间资源（表）
	 * 
	 * @param dmTaskPO
	 *            任务实例
	 * @return 是否继续执行
	 */
	private boolean checkTableSpaceForTable(DmTaskPO dmTaskPO) {
		logger.info("检测表空间资源（表）TASKID={0}-------",dmTaskPO.getDmTaskId());
		List<Map<String, Object>> tSpaceList = null;//表空间
		DmTaskStageArg taskStageArg = new DmTaskStageArg();
		DmTaskStageArg.DmTaskStageCriteria taskStageCriteria = taskStageArg.createCriteria();
		taskStageCriteria.andDmTaskIdEqualTo(dmTaskPO.getDmTaskId());
		taskStageCriteria.andStageEqualTo(0);//体检
		taskStageCriteria.andStateNotEqualTo("00F");
		List<DmTaskStagePO> dmTaskStagePOList = dmTaskStageDao.selectByArg(taskStageArg);
		if (Utils.isEmpty(dmTaskStagePOList)) {
			logger.info("获取体检非失败环节为空 TASKID={0}-------",dmTaskPO.getDmTaskId());
			return false;
		}
		DbBaseInfoPO dbBaseInfoPO = null;
		DmSrcTablePO srcTablePO = null;
		Map<String, String> tableMap = null;
		String dbType = null;
		try {
			for (DmTaskStagePO dmTaskStagePO : dmTaskStagePOList) {
				//查询源对象
				srcTablePO = srcTableCustomDao.selectByStrategyId(dmTaskStagePO.getDmStrategyId());
				
				dbBaseInfoPO = dbBaseInfoDao.selectByLinkId(srcTablePO.getDbLinkId());
				hostMap.put(dbBaseInfoPO.getDbHostIp(), dbBaseInfoPO.getDbBaseId());//主机信息
				
				dbType = dbBaseInfoDao.selectByLinkId(srcTablePO.getDbLinkId())
						.getDbCategory().toUpperCase();
				
	//			if (DMSConstant.DB_LINK_CATEGORY_MDB.equals(dbType)) return false;
				
				tableMap = new HashMap<String, String>(); 
				String tableKey = srcTablePO.getDbLinkId()+";"+srcTablePO.getDbUserName()+";"+dbType;
				tableMap.put(tableKey, srcTablePO.getTableName());
				//查询目标对象
				List<DmTargetTablePO> targetTableList = dmTargetTableDao
						.selectAllByStrategyId(dmTaskStagePO.getDmStrategyId());
				logger.debug("目标表size:{0}",targetTableList.size());
				for (DmTargetTablePO targetPO : targetTableList) {
					dbBaseInfoPO = dbBaseInfoDao.selectByLinkId(srcTablePO.getDbLinkId());
					hostMap.put(dbBaseInfoPO.getDbHostIp(),dbBaseInfoPO.getDbBaseId());//主机信息
					dbType = dbBaseInfoDao.selectByLinkId(targetPO.getDbLinkId())
							.getDbCategory().toUpperCase();
					if (DMSConstant.DB_LINK_CATEGORY_MDB.equals(dbType)) continue;
					if (tableMap.keySet().contains(targetPO.getDbLinkId()+";"+targetPO.getDbUserName()+";"+dbType)) {
						tableMap.put(tableKey, tableMap.get(tableKey)+";"+targetPO.getTableName());
					} else {
						tableMap.put(targetPO.getDbLinkId()+";"+targetPO.getDbUserName()+";"+dbType, targetPO.getTableName());
					}
				}
				String[] keyArr;
				String[] tableArr;
				String[] targetDbConfig;
				for (Entry<String, String> tableEntry : tableMap.entrySet()) {
					keyArr = tableEntry.getKey().split(";");
					tableArr = tableEntry.getValue().split(";");
					targetDbConfig = baseInfoService.getDbConfig(Integer.parseInt(keyArr[0]), keyArr[1]);
					tSpaceList = qryTSpace(targetDbConfig, Integer.parseInt(keyArr[0]), tableArr, keyArr[2], dmTaskPO);
					/*
					 * 处理结果查询
					 */
					if (dealTSpace(dmTaskPO, tSpaceList, keyArr[2], Integer.parseInt(keyArr[0]))){
						hostMap.clear();
						return false;//表空间超过阀值~
					};
				}
			}
		} catch (Exception e) {
			logger.error("处理表空间查询异常",e);
			return true;//默认正常,避免其他任务无法执行
		}
		return true;
	}

	private boolean dealTSpace(DmTaskPO dmTaskPO,List<Map<String, Object>> tSpaceList, String dbType, Integer dbLinkId) {
		if (tSpaceList == null || tSpaceList.size() == 0) return false;
		boolean flag = false;
		for (Map<String, Object> tspaceMap : tSpaceList) {
			DetectionInfoPO po = new DetectionInfoPO();
			po.setDmTaskId(dmTaskPO.getDmTaskId());
			po.setDetectionType(DMSConstant.DETECTION_TYPE_DB);
			po.setDetectionObjectType(dbType);
			po.setDetectionObjectId(dbLinkId);
			po.setDetectionItemName(DMSConstant.DETECTION_ITEM_TABLESPACE);
			po.setDetectionTotalResult(BigDecimal.valueOf((Double)tspaceMap.get("totalSpace")));
			po.setDetectionUsedResult(BigDecimal.valueOf((Double)tspaceMap.get("totalSpace") - 
					(Double)tspaceMap.get("freeSpace")));
			po.setDetectDate(DateUtils.getNowDate());
			po.setNodeId(dmTaskPO.getNodeId());
			logger.info("空间已使用量:{0},阀值:{1}",tspaceMap.get("usedPct"),tbsUsedThreshold);
			po.setWarningFlag(0);
			if (tbsUsedThreshold <= (Float)tspaceMap.get("usedPct")) {
				po.setWarningFlag(1);
				TaskNotify notify = DMSConstant.taskInstList.get(dmTaskPO.getDmTaskId());
				if (Utils.isEmpty(notify)) notify = new TaskNotify();
				logger.debug(dmTaskPO.getDmTaskId() + "的修改前编码：" + notify.getStatus());
				notify.setDealType("TBS-USED");
				notify.setStatus(DMSConstant.Status.SYSPAUSE.toString());
				notify.setDealDesc("表空间" + tspaceMap.get("spaceName")+ 
						"使用率为" + tspaceMap.get("usedPct") + "%，达到系统设置的阀值" + tbsUsedThreshold + "%，需要暂停任务");
				DMSConstant.taskInstList.put(dmTaskPO.getDmTaskId(), notify);
				logger.debug(dmTaskPO.getDmTaskId() + "的修改后编码：" + notify.getStatus());
				// 向IOCP推送告警信息
				Map<String, String> paramMap = new HashMap<String, String>();
				paramMap.put("warningName",notify.getDealType()+ dmTaskPO.getDmTaskId());
				paramMap.put("warningLevel", "urgent");
				paramMap.put("warningType", "10A");
				paramMap.put("createdTime",DateUtils.getCurrentDate().replace(" ", "%20"));
				try {
					paramMap.put("warningReason", URLEncoder.encode(notify.getDealDesc(),"UTF-8"));
					paramMap.put("warningDesc", URLEncoder.encode(notify.getDealDesc(),"UTF-8"));
				} catch (UnsupportedEncodingException e) {
				}
				paramMap.put("subSysIp", subSysIp);
				paramMap.put("subSysPort", subSysPort);
				pushMsg2IOCP(paramMap, collectUrl);
				logger.info("向IOCP推送告警信息 OK");
				flag = true;
			}
			saveOrUpdateData(po);
			if (flag) return flag;
		}
		return flag;
	}

	private List<Map<String, Object>> qryTSpace(String[] dbConfig, Integer dbLinkId, String[] tableNameArr,
			String dbType, DmTaskPO dmTaskPO) throws BaseAppException {
		Connection con = null;
		PreparedStatement stmt = null;
		DataSource dataSource = null;
		ResultSet rs = null;
		String spaceName = null;
		double totalSpace = 0;
		double freeSpace = 0;
		BigDecimal usedPct;
		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		Map<String, Object> resultMap = null;
		try {
			logger.debug("|连接数据库|");
			dataSource = dynamicDataSourceManager.getDruidDataSource(dbLinkId+dbConfig[2], dbConfig);
			logger.debug("||获取数据库连接中...");
			con = DataSourceUtils.getConnection(dataSource);
			logger.debug("获取链接信息ok...");
			for (String tableName : tableNameArr) {				
				String sql = Util.getSQLByDBType(dbType, tableName, dbConfig[4]);
				logger.debug("|查询表空间SQL|:{0}",sql);
				//显示~
				JdbcUtils.closeStatement(stmt);
				JdbcUtils.closeResultSet(rs);
				
				stmt = con.prepareStatement(sql);
				rs = stmt.executeQuery();
				logger.debug("|查询表空间OK|");
				if (rs.next()) {
					spaceName = rs.getString(1);
					freeSpace = rs.getDouble(2);
					totalSpace = rs.getDouble(3);
					
					resultMap = new HashMap<String, Object>();;
					resultMap.put("spaceName", spaceName);
					resultMap.put("freeSpace", freeSpace);
					resultMap.put("totalSpace", totalSpace);
					usedPct = BigDecimal.valueOf(100 * (totalSpace - freeSpace) / totalSpace).setScale(2, RoundingMode.HALF_UP);
					resultMap.put("usedPct", usedPct.floatValue());
					list.add(resultMap);
					if (tbsUsedThreshold < usedPct.floatValue()) {			
						break;
					} else {
						continue;
					}
				}
			}
		} catch (Exception e) {
			throw ExceptionHandler.publish("监测表空间异常|", e);
		} finally {
				JdbcUtils.closeStatement(stmt);
				JdbcUtils.closeResultSet(rs);
				DataSourceUtils.releaseConnection(con,dataSource);
		}
		
		return list;
	}

	private void saveOrUpdateData(DetectionInfoPO po) {
		DetectionInfoArg arg = new DetectionInfoArg();
		DetectionInfoArg.DetectionInfoCriteria c = arg.createCriteria();
		c.andDmTaskIdEqualTo(po.getDmTaskId());
		c.andDetectionObjectIdEqualTo(po.getDetectionObjectId());
		c.andDetectionTypeEqualTo(po.getDetectionType());
		c.andDetectionItemNameEqualTo(po.getDetectionItemName());
		List<DetectionInfoPO> list = detectionInfoDao.selectByArg(arg);
		if (list.size() > 0) {
			po.setDetectionId(list.get(0).getDetectionId());
			detectionInfoDao.updateByPrimaryKey(po);
		} else {
			try {
				po.setDetectionId(sequenceGenerator.sequenceLongValue("DETECTION_INFO", "DETECTION_ID"));
			} catch (BaseAppException e) {//skip
			}
			detectionInfoDao.insert(po);
		}
	}

	/**
	 * 向iocp推送告警信息
	 * @throws UnsupportedEncodingException 
	 */
	public String pushMsg2IOCP(String warningName, String warningReason, String warningDesc)  {
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("warningLevel", "urgent");
		paramMap.put("warningType", "10A");
		paramMap.put("createdTime", DateUtils.getCurrentDate().replace(" ", "%20"));
		try {
			paramMap.put( "warningName", URLEncoder.encode(warningName ,"UTF-8"));
			paramMap.put("warningReason", URLEncoder.encode(warningReason ,"UTF-8"));
			paramMap.put("warningDesc", URLEncoder.encode(warningDesc,"UTF-8"));
		} catch (UnsupportedEncodingException e) {//skip
		}
		if (Utils.isEmpty(collectUrl)){
			initSysParam();
		}
		paramMap.put("subSysIp", subSysIp);
		paramMap.put("subSysPort", subSysPort);
		return pushMsg2IOCP(paramMap, collectUrl);
	}
	
	/**
	 * 告警推送
	 * @param paramMap
	 * @param url
	 * @return
	 */
	public String pushMsg2IOCP(Map<String, String> paramMap, String url) {
		try {
			HttpUtils.getDataByUrl(url + "?" + Util.bldMap2Str(paramMap));
			return "success";
		} catch (Exception e) { 
			logger.error("DMM推送告警信息失败",e);
			return "fail";
		}
	}

	
	/**
	 * 查询系统参数表，初值
	 */
	private void initSysParam() {
		hostMap = new HashMap<String, Integer>();//初始化
		SysParamArg sysParamArg = new SysParamArg();
		SysParamArg.SysParamCriteria sysParamCriteria = sysParamArg
				.createCriteria();
		sysParamCriteria.andStateEqualTo(DMSConstant.Status.SUCCESS.toString());
		List<SysParamPO> syspParamList = sysParamDao.selectByArg(sysParamArg);
		for (SysParamPO sysParamPO : syspParamList) {
			if ("BUS_START_TIME".equals(sysParamPO.getParamName())) {
				busStartTime = sysParamPO.getParamValue();
			} else if ("BUS_END_TIME".equals(sysParamPO.getParamName())) {
				busEndTime = sysParamPO.getParamValue();
			} else if ("CPU_USED_THRESHOLD".equals(sysParamPO.getParamName())) {
				cpuUsedThreshold = Float.valueOf(sysParamPO.getParamValue());
			} else if ("MEM_USED_THRESHOLD".equals(sysParamPO.getParamName())) {
				memUsedThreshold = Float.valueOf(sysParamPO.getParamValue());
			} else if ("TBS_USED_THRESHOLD".equals(sysParamPO.getParamName())) {
				tbsUsedThreshold = Float.valueOf(sysParamPO.getParamValue());
			} else if ("collect.do".equals(sysParamPO.getParamName())) {
				collectUrl = sysParamPO.getParamValue();
			} else if ("clean.do".equals(sysParamPO.getParamName())) {
				cleanUrl = sysParamPO.getParamValue();
			} else if ("subSysIp".equals(sysParamPO.getParamName())) {
				subSysIp = sysParamPO.getParamValue();
			} else if ("subSysPort".equals(sysParamPO.getParamName())) {
				subSysPort = sysParamPO.getParamValue();
			}
		}
	}
	
	private String qryDealType(String name) {
		String dealType = null;
		if (DMSConstant.DETECTION_ITEM_CPU.equals(name)) {
			dealType = "CPU_USED";
		} else if (DMSConstant.DETECTION_ITEM_MEMORY.equals(name)) {
			dealType = "MEM_USED";
		} else if (DMSConstant.DETECTION_ITEM_TABLESPACE.equals(name)) {
			dealType = "TBS_USED";
		} else if (DMSConstant.DETECTION_ITEM_DISKSPACE.equals(name)) {
			dealType = "DISK_USED";
		}
		return dealType;
	}
}
